/***************************************************************************
 *   This file is part of KLabeler                                         *
 *   Copyright (C) 2010 by Luca Bellonda                                   *
 *   lbellonda _at_ gmail.com                                              *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "AssignTagWorker.h"
#include <QDBusPendingReply>
#include <KMessageBox>
#include <KLocale>

#include "klabeler_interface.h"

#define SOURCE_CLASS "AssignTagsWorker"


class AssignTagsWorker::OperationDebug : public AssignTagsWorker::Operation
{
public:
    OperationDebug(AssignTagsWorker *_owner);
    virtual ~OperationDebug();
    virtual void start() ;
    virtual void end(const bool isError, const int errorCode, const QString &errorMessage) ;
};

class AssignTagsWorker::OperationAssign : public AssignTagsWorker::Operation
{
public:
    OperationAssign(AssignTagsWorker *_owner);
    virtual ~OperationAssign();
    virtual void start() ;
    virtual void end(const bool isError, const int errorCode, const QString &errorMessage) ;
};

class AssignTagsWorker::OperationConfigure : public AssignTagsWorker::Operation
{
public:
    OperationConfigure(AssignTagsWorker *_owner);
    virtual ~OperationConfigure();
    virtual void start() ;
    virtual void end(const bool isError, const int errorCode, const QString &errorMessage) ;
};

class AssignTagsWorker::OperationAssignOtherTags : public AssignTagsWorker::Operation
{
public:
    OperationAssignOtherTags(AssignTagsWorker *_owner);
    virtual ~OperationAssignOtherTags();
    virtual void start() ;
    virtual void end(const bool isError, const int errorCode, const QString &errorMessage) ;
};

class AssignTagsWorker::OperationChooseProfile : public AssignTagsWorker::Operation
{
public:
    OperationChooseProfile(AssignTagsWorker *_owner);
    virtual ~OperationChooseProfile();
    virtual void start() ;
    virtual void end(const bool isError, const int errorCode, const QString &errorMessage) ;
};

//-------------------------------------------------------------------------------------------------------


AssignTagsWorker::AssignTagsWorker(QObject* parent)
{
    _isDebug = false;
    _count = 0;
    _operation = NULL ;
    initLog();
}

AssignTagsWorker::~AssignTagsWorker()
{
    clearOperation();
}

void AssignTagsWorker::setOperation(Operation *newOperation)
{
    clearOperation();
    _operation = newOperation ;
}

void AssignTagsWorker::clearOperation()
{
    if (NULL != _operation) {
        delete _operation ;
        _operation = NULL ;
    }
}

void AssignTagsWorker::run()
{
    logger.debug(&_logParams, "run()");
    _started = false;
    _count = 0 ;
    connect(&_timer, SIGNAL(timeout()), this, SLOT(updateProgress()));
    _timer.start(1000);   // one second interval
    exec();
    logger.debug(&_logParams, "loop end");
    _timer.stop();
    endProcessing(false, 0, "done");
    clearOperation();
}


void AssignTagsWorker::endProcessing(const bool isError, const int errorCode, const QString &errorMessage)
{
    logger.debug(&_logParams, "end job");
    if (NULL != _operation) {
        _operation->end(isError, errorCode, errorMessage);
    }
}


void AssignTagsWorker::updateProgress()
{
    emit tick();
    _count++;
    if (_isDebug) {
        // force exit
        if (_count > 2) {
            // here we should talk via d-bus to server and listen for response
            callInterface();
            logger.debug(&_logParams, "..exiting...");
            exit();
        }
    } else {
        if (!_started) {
            _started = true;
            logger.debug(&_logParams, "start job ");
            if (NULL != _operation) {
                _operation->start();
            }
            logger.debug(&_logParams, "..exiting...");
            exit();
        }
    }
}

void AssignTagsWorker::callDebug()
{
    logger.debug(&_logParams, "callDebug");
    if (!isRunning()) {
        _isDebug = true ;
        setOperation(allocOperation(new OperationDebug(this)));
        start(LowPriority);
    }
}

void AssignTagsWorker::assignOtherTags(const QString &activityName, const QString &resource)
{
    logger.debug(&_logParams, "assignOtherTags");
    if (!isRunning()) {
        _resource = resource ;
        _isDebug = false;
        _currentActivity = activityName ;
        setOperation(allocOperation(new OperationAssignOtherTags(this)));
        start(LowPriority);
    }
}

void AssignTagsWorker::assignFiles(const QString &activityName, const QStringList & fileList)
{
    logger.debug(&_logParams, "assignFiles");
    if (!isRunning()) {
        _isDebug = false;
        _fileList = fileList;
        _currentActivity = activityName ;
        setOperation(allocOperation(new OperationAssign(this)));
        start(LowPriority);
    }
}

void AssignTagsWorker::configure()
{
    logger.debug(&_logParams, "configure");
    if (!isRunning()) {
        _isDebug = false;
        setOperation(allocOperation(new OperationConfigure(this)));
        start(LowPriority);
    }
}

void AssignTagsWorker::chooseProfile()
{
    logger.debug(&_logParams, "chooseProfile");
    if (!isRunning()) {
        _isDebug = false;
        setOperation(allocOperation(new OperationChooseProfile(this)));
        start(LowPriority);
    }
}

AssignTagsWorker::Operation *AssignTagsWorker::allocOperation(Operation *operation)
{
    if (NULL == operation) {
        KMessageBox::error(NULL, i18n("Can't start operation"), APP_TITLE);
    }
    return operation ;
}

void AssignTagsWorker::callInterface()
{
    logger.debug(&_logParams, "calling interface");
    org::kde::klabeler::App *appl = new org::kde::klabeler::App(APPL_SERVICE_NAME, MAIN_DBUS_OBJECT, QDBusConnection::sessionBus());
    if (NULL != appl) {
        logger.debug(&_logParams, "before calling interface");
        QDBusPendingReply<int> reply = appl->prova();
        reply.waitForFinished();
        if (reply.isError()) {
            logger.error(&_logParams, "ERROR CALLING");
            QDBusError error = reply.error();
            logger.debug(&_logParams, QString("msg='%1', name='%2' type='%3'").arg(error.message()).arg(error.name()).arg(error.type()));
        } else {
            int result = reply.value();
            logger.debug(&_logParams, QString("result is %1").arg(result));
        }
        logger.debug(&_logParams, "end calling interface");
        delete appl;
    }
}

void AssignTagsWorker::callAssignOtherTags()
{
    logger.debug(&_logParams, "calling callAssignOtherTags");
    org::kde::klabeler::App *appl = new org::kde::klabeler::App(APPL_SERVICE_NAME, MAIN_DBUS_OBJECT, QDBusConnection::sessionBus());
    if (NULL != appl) {
        logger.debug(&_logParams, "before calling interface");
        QDBusPendingReply<> reply = appl->assignOtherTags(_currentActivity, _resource);
        reply.waitForFinished();
        if (reply.isError()) {
            logger.error(&_logParams, "ERROR CALLING");
            QDBusError error = reply.error();
            logger.debug(&_logParams, QString("msg='%1', name='%2' type='%3'").arg(error.message()).arg(error.name()).arg(error.type()));
        }
        logger.debug(&_logParams, "end calling interface");
        delete appl;
    }
}

void AssignTagsWorker::xmitStrings()
{
    /* TODO
    logger.debug(&_logParams, "calling interface assign");
    org::kde::klabeler::App *appl = new org::kde::klabeler::App(APPL_SERVICE_NAME, MAIN_DBUS_OBJECT, QDBusConnection::sessionBus());
    if (NULL != appl) {
        logger.debug(&_logParams, "before calling interface");
        QDBusPendingReply<bool> reply = appl->setTagsToList( _currentActivity,  _fileList );
        reply.waitForFinished();
        if (reply.isError()) {
            logger.error(&_logParams, "ERROR CALLING");
            QDBusError error = reply.error();
            logger.debug(&_logParams, QString("msg='%1', name='%2' type='%3'").arg(error.message()).arg(error.name()).arg(error.type()));
        } else {
            int result = reply.value();
            logger.debug(&_logParams, QString("result is %1").arg(result));
        }
        logger.debug(&_logParams, "end calling interface");
        delete appl;
    }
    */
}

void AssignTagsWorker::callConfigure()
{
    logger.debug(&_logParams, "calling interface configure");
    org::kde::klabeler::App *appl = new org::kde::klabeler::App(APPL_SERVICE_NAME, MAIN_DBUS_OBJECT, QDBusConnection::sessionBus());
    if (NULL != appl) {
        logger.debug(&_logParams, "before calling interface");
        QDBusPendingReply<> reply = appl->configure();
        reply.waitForFinished();
        if (reply.isError()) {
            logger.error(&_logParams, "ERROR CALLING");
            QDBusError error = reply.error();
            logger.debug(&_logParams, QString("msg='%1', name='%2' type='%3'").arg(error.message()).arg(error.name()).arg(error.type()));
        }
        logger.debug(&_logParams, "end calling interface");
        delete appl;
    }
}


void AssignTagsWorker::callChooseProfile()
{
    logger.debug(&_logParams, "calling interface chooseProfile");
    org::kde::klabeler::App *appl = new org::kde::klabeler::App(APPL_SERVICE_NAME, MAIN_DBUS_OBJECT, QDBusConnection::sessionBus());
    if (NULL != appl) {
        logger.debug(&_logParams, "before calling interface");
        QDBusPendingReply<> reply = appl->chooseCurrentProfile();
        reply.waitForFinished();
        if (reply.isError()) {
            logger.error(&_logParams, "ERROR CALLING");
            QDBusError error = reply.error();
            logger.debug(&_logParams, QString("msg='%1', name='%2' type='%3'").arg(error.message()).arg(error.name()).arg(error.type()));
        }
        logger.debug(&_logParams, "end calling interface");
        delete appl;
    }
}

QStringList AssignTagsWorker::callGetTags(const QString &activityName)
{
    QStringList result;
    logger.debug(&_logParams, "calling interface getProfileTags");
    org::kde::klabeler::App *appl = new org::kde::klabeler::App(APPL_SERVICE_NAME, MAIN_DBUS_OBJECT, QDBusConnection::sessionBus());
    if (NULL != appl) {
        logger.debug(&_logParams, "before calling interface");
        bool isOk = true ;
        QDBusPendingReply<QStringList, bool> reply =  appl->getActivityTags(activityName);
        reply.waitForFinished();
        if (reply.isError()) {
            logger.error(&_logParams, "ERROR CALLING");
            QDBusError error = reply.error();
            logger.debug(&_logParams, QString("msg='%1', name='%2' type='%3'").arg(error.message()).arg(error.name()).arg(error.type()));
        } else {
            isOk = reply.argumentAt<1>();
            if (isOk) {
                result = reply.argumentAt<0>();
            }
            //logger.debug(&_logParams, QString("result is %1").arg(result).to);
        }
        logger.debug(&_logParams, "end calling interface");
        delete appl;
    }
    return result;
}


void AssignTagsWorker::initLog()
{
    _logParams.source = SOURCE_CLASS;
}

void AssignTagsWorker::emitProcessFinished(const bool isError, const int errorCode, const QString &errorMessage)
{
    emit processFinished(isError, errorCode, errorMessage);
}

void AssignTagsWorker::emitProcessProfileFinished(const bool isError, const int errorCode, const QString &errorMessage)
{
    emit processProfileFinished(isError, errorCode, errorMessage);
}

//------------------------------------------------------------------------------------------------

AssignTagsWorker::Operation::Operation(AssignTagsWorker *owner)
{
    _owner = owner ;
}
AssignTagsWorker::Operation::~Operation()
{
}

AssignTagsWorker::OperationDebug::OperationDebug(AssignTagsWorker *owner) : Operation(owner)
{
}

AssignTagsWorker::OperationDebug::~OperationDebug()
{
}
void AssignTagsWorker::OperationDebug::start()
{
    _owner->callInterface();
}
void AssignTagsWorker::OperationDebug::end(const bool isError, const int errorCode, const QString &errorMessage)
{
    _owner->emitProcessFinished(isError, errorCode, errorMessage);
}
//-------------------------------------------------------------------------------------------------
AssignTagsWorker::OperationAssign::OperationAssign(AssignTagsWorker *owner) : Operation(owner)
{
}

AssignTagsWorker::OperationAssign::~OperationAssign()
{
}
void AssignTagsWorker::OperationAssign::start()
{
    _owner->xmitStrings();
}
void AssignTagsWorker::OperationAssign::end(const bool isError, const int errorCode, const QString &errorMessage)
{
    _owner->emitProcessProfileFinished(isError, errorCode, errorMessage);
}
//-------------------------------------------------------------------------------------------------
AssignTagsWorker::OperationConfigure::OperationConfigure(AssignTagsWorker *owner) : Operation(owner)
{
}

AssignTagsWorker::OperationConfigure::~OperationConfigure()
{
}
void AssignTagsWorker::OperationConfigure::start()
{
    _owner->callConfigure();
}
void AssignTagsWorker::OperationConfigure::end(const bool isError, const int errorCode, const QString &errorMessage)
{
    _owner -> emit configurationFinished();
}
//-------------------------------------------------------------------------------------------------
AssignTagsWorker::OperationAssignOtherTags::OperationAssignOtherTags(AssignTagsWorker *owner) : Operation(owner)
{
}

AssignTagsWorker::OperationAssignOtherTags::~OperationAssignOtherTags()
{
}
void AssignTagsWorker::OperationAssignOtherTags::start()
{
    _owner->callAssignOtherTags();
}
void AssignTagsWorker::OperationAssignOtherTags::end(const bool isError, const int errorCode, const QString &errorMessage)
{
    _owner->emitProcessFinished(isError, errorCode, errorMessage);
}
//-------------------------------------------------------------------------------------------------
AssignTagsWorker::OperationChooseProfile::OperationChooseProfile(AssignTagsWorker *owner) : Operation(owner)
{
}

AssignTagsWorker::OperationChooseProfile::~OperationChooseProfile()
{
}
void AssignTagsWorker::OperationChooseProfile::start()
{
    _owner->callChooseProfile();
}
void AssignTagsWorker::OperationChooseProfile::end(const bool isError, const int errorCode, const QString &errorMessage)
{
    _owner -> emit configurationFinished();
}

//------------------------------------------------------------------------------
